/*
 * ynfs main function
 */
#include "config.h"

#include <sys/types.h>
#include <sys/wait.h>
#include <rpc/pmap_clnt.h>
#include <errno.h>
#include <getopt.h>

#define DBG_SUBSYS S_LIBINTERFACE

#include "get_version.h"
#include "stat_cache.h"
#include "job_dock.h"
#include "nfs_events.h"
#include "nfs_state_machine.h"
#include "nlm_events.h"
#include "sysy_lib.h"
#include "sunrpc_passive.h"
#include "sunrpc_proto.h"
#include "xdr_nfs.h"
#include "ynet_rpc.h"
#include "ynfs_conf.h"
#include "lich_nfs.h"
#include "lichstor.h"
#include "configure.h"
#include "nfs_proc.h"
#include "net_table.h"
#include "dbg.h"

/* register with portmapper ? */
int opt_portmapper = 1;
extern uint32_t nfs_read_max_size;

int register_nfs_service()
{
        int ret;

        if (opt_portmapper)
                pmap_unset(NFS3_PROGRAM, NFS_V3);

        if (! pmap_set (NFS3_PROGRAM, NFS_V3, opt_portmapper ? IPPROTO_TCP : 0,
                        2049)) {
                ret = EAGAIN;
                GOTO(err_ret, ret);
        }

        return 0;
err_ret:
        return ret;
}

int register_mount_service()
{
        int ret;

        if (opt_portmapper) {
                pmap_unset(MOUNTPROG, MOUNTVERS3);
        }

        if (! pmap_set (MOUNTPROG, MOUNTVERS3, opt_portmapper ? IPPROTO_TCP : 0,
                        2049)) {
                ret = EAGAIN;
                GOTO(err_ret, ret);
        }

        return 0;
err_ret:
        return ret;
}

int register_nlm_service()
{
        int ret;

        if (opt_portmapper)
                pmap_unset(NLM_PROGRAM, NLM_VERSION);

        if (! pmap_set (NLM_PROGRAM, NLM_VERSION, opt_portmapper ? IPPROTO_TCP : 0,
                        2049)) {
                ret = EAGAIN;
                GOTO(err_ret, ret);
        }
        return 0;
err_ret:
        return ret;
}

static int __nfs_run()
{
        int ret;

        ret = sunrpc_tcp_passive(NFS_SERVICE_DEF);
        if (unlikely(ret)) {
                goto err_ret;
        }

        /* init write verifier */

        regenerate_write_verifier();

        ret = register_mount_service();
        if (unlikely(ret)) {
                DERROR("you need portmap installed...\n");
                GOTO(err_ret, ret);
        }

        ret = register_nfs_service();
        if (unlikely(ret)) {
                DERROR("you need portmap installed...\n");
                GOTO(err_ret, ret);
        }

#if 0
        ret = register_nlm_service();
        if (unlikely(ret)) {
                DERROR("you need portmap installed...\n");
                GOTO(err_ret, ret);
        }
#endif

        return 0;
err_ret:
        return ret;
}

static void *__nfs_service(void *_arg)
{
        int ret;

        (void) _arg;
        DINFO("start...\n");

        while (1) {
                ret = __nfs_run();
                if (unlikely(ret)) {
                        if (ret == EADDRINUSE) {
                                //DBUG("retry nfs\n");
                                sleep(2);
                                continue;
                        } else
                                GOTO(err_ret, ret);
                }

                DINFO("nfs service inited\n");

                break;
        }

        return NULL;
err_ret:
        return NULL;
}


int nfsd_srv()
{
        int ret;
        pthread_t th;
        pthread_attr_t ta;
        //const char *service = NFS_SERVICE_DEF;

        ret = mountlist_init();
        if (unlikely(ret))
                GOTO(err_ret, ret);

        (void) pthread_attr_init(&ta);
        (void) pthread_attr_setdetachstate(&ta,PTHREAD_CREATE_DETACHED);

        ret = pthread_create(&th, &ta, __nfs_service, NULL);
        if (unlikely(ret))
                GOTO(err_ret, ret);

        return 0;
err_ret:
        return ret;
}
